<template>
  <el-form v-bind="$attrs" ref="formRef" :model="form" label-suffix=":" :label-width="labelWidth">
    <el-form-item
      v-for="item in items"
      :key="item.prop"
      :label="item.label"
      :prop="item.prop"
      :rules="
        item.rules && {
          required: item.rules.required,
          message: item.rules.message || item.placeholder || item.label + '是必填项',
          trigger: item.rules.trigger || 'change'
        }
      "
    >
      <template v-if="['input', 'textarea'].includes(item.type)">
        <el-input
          :type="item.type"
          v-bind="item.custom"
          v-model="form[item.prop]"
          :placeholder="item.placeholder"
        />
      </template>
      <template v-if="item.type === 'select'">
        <el-select v-bind="item.custom" v-model="form[item.prop]" placeholder="">
          <el-option
            v-for="v in item.options"
            :key="v[item.selectVal]"
            :label="v[selectLabel(item)]"
            :value="v[getValue(item)]"
          />
        </el-select>
      </template>
      <template v-if="item.type === 'date'">
        <el-date-picker v-bind="item.custom" v-model="form[item.prop]" />
      </template>
      <template v-if="item.type === 'radio'">
        <el-radio-group v-bind="item.custom" v-model="form[item.prop]">
          <el-radio v-for="v in item.options" :key="v[getValue(item)]" :label="v[getValue(item)]">
            {{ v[selectLabel(item)] }}
          </el-radio>
        </el-radio-group>
      </template>
      <template v-if="item.type === 'checkbox'">
        <el-checkbox-group v-bind="item.custom" v-model="form[item.prop]">
          <el-checkbox
            v-for="v in item.options"
            :key="v[getValue(item)]"
            :label="v[getValue(item)]"
          >
            {{ v[selectLabel(item)] }}
          </el-checkbox>
        </el-checkbox-group>
      </template>
      <template v-if="item.type === 'switch'">
        <el-switch v-bind="item.custom" v-model="form[item.prop]"></el-switch>
      </template>
      <template v-if="item.type === 'slot'">
        <slot :name="item.slot" :item="item" />
      </template>
    </el-form-item>
  </el-form>
</template>

<script lang="ts">
import { computed, defineComponent, reactive, toRefs, ref, watch } from 'vue'
import { ElForm } from 'element-plus'

export default defineComponent({
  props: {
    labelWidth: {
      type: String,
      default: '90px'
    },
    items: {
      type: Array,
      default: () => []
    },
    modelValue: {
      type: Object,
      default: () => {}
    }
  },
  setup(props, { emit }) {
    const formRef = ref<typeof ElForm>()

    const form = computed(() => props.modelValue)

    watch(
      () => form,
      (value) => {
        emit('update:modelValue', value)
      },
      { deep: true }
    )

    const state = reactive({
      selectLabel(item: { selectLabel: string }) {
        return item.selectLabel || 'label'
      },
      getValue(item: { selectValue: string }) {
        return item.selectValue || 'value'
      }
    })

    const validate = () => {
      return new Promise((resolve, reject) => {
        formRef.value &&
          formRef.value
            .validate()
            .then((valid: boolean) => {
              resolve(valid)
            })
            .catch((err: any) => {
              reject(err)
            })
      })
    }

    return {
      ...toRefs(state),
      form,
      formRef,
      validate
    }
  }
})
</script>
